#include "Sphere.h"
#include "Ray.h"
#include "ContactData.h"

/* Virtual implementation of Renderable Hit() function */
bool Sphere::Hit( const Ray& ray, float& tmin, ContactData& data ) const
{
    float 		t;
    //vec from ray to center of sphere
    Vec3	temp 	= ray.m_origin - m_pos;
    //rays radius squared
    float 		a 		= ray.m_dir.DotProduct(ray.m_dir);
    //dot product of the rays direction and the ray to center vector ( why * 2 ?? )
    float 		b 		= (temp*2.0f).DotProduct(ray.m_dir);
    //temp dot temp is its squared length
    //c is squared distance from ray origin to center
    float 		c 		= temp.DotProduct(temp) - m_rad * m_rad;

    //the discriminant
    float 		disc	= b * b - 4.0f * a * c;

    //if its less than 0, we are out of here!
    if (disc < 0.0)
        return(false);
    else 
    {
        //
        float e = sqrt(disc);
        float denom = 2.0f * a;
        data.m_hitTarget = (Renderable*)this;

        t = (-b - e) / denom;    // smaller root
        if (t > 0.001f) 
        {
            tmin = t;
            ray.m_depth = tmin; 
            data.m_hitNormal = (temp + (ray.m_dir * t)) / m_rad;
            data.m_hitNormal.normalise();
            data.m_hitPoint = ray.m_origin + ray.m_dir * t;
            return (true);
        } 
        t = (-b + e) / denom;    // larger root
        if (t > 0.001f) 
        {   
            tmin = t;
            ray.m_depth = tmin; 
            data.m_hitNormal = (temp + (ray.m_dir * t)) / m_rad;
            data.m_hitNormal.normalise();
            data.m_hitPoint = ray.m_origin + ray.m_dir * t;
            return (true);
        } 
        return (false);
    }

    return (false);
}

void Sphere::SetPosition( float x, float y, float z )
{
    m_pos.SetStats(x,y,z);
}

void Sphere::SetRadius( float rad )
{
    m_rad = rad;
}

